package pl;

import javacard.framework.JCSystem;
import javacard.framework.Util;

public class PrimitiveBERTLV extends BERTLV {

	byte[] temArr;
	
	public PrimitiveBERTLV(short numValueBytes) 
	{
		//theValue = JCSystem.makeTransientByteArray(numValueBytes, JCSystem.CLEAR_ON_DESELECT);
		theValue = new byte[numValueBytes];
	}
	
	// TODO: Add exceptions
	public short init(byte[] bArray, short bOff, short bLen) 
	{
		short offset = 0;	
		
		temArr = new byte[bLen]; //JCSystem.makeTransientByteArray(bLen, JCSystem.CLEAR_ON_DESELECT);	
		Util.arrayCopy(bArray, bOff, temArr, MediatorFE.O, bLen);
		
		//if (verifyFormat(temArr, Aplet.O, (short)temArr.length))
		if (verifyFormat(bArray, bOff , bLen))
		{
			// tag
			theBERTag = PrimitiveBERTag.getInstance(temArr, (short)0);
			
			if (theBERTag.size() == 0x01) offset++;
			else if (theBERTag.size() == 0x02) offset += 2;
			
			// length
			if ((temArr[offset] & 0x80) != 0x80) 
			{
				this.valueLength = temArr[offset];
				offset++;
			}
			else
			{
				if ((temArr[offset] & 0x03) == 0x01) 
				{	
					this.valueLength = (short) (temArr[(short)(offset + 1)] & 0x00FF);	
					offset += 2;
				}
				else if (((temArr[offset] & 0x03) == 0x02))
				{
					this.valueLength = MediatorFE.byteArrayToShort(new byte[]
					       {
								temArr[(byte)(offset + 2)], 
								temArr[(byte)(offset + 1)]
					       });
					
					offset += 3;
				}
			}	

			// value
			//theValue = JCSystem.makeTransientByteArray(valueLength, JCSystem.CLEAR_ON_DESELECT);
			Util.arrayCopy(temArr, offset, theValue, MediatorFE.O, valueLength);	
			this.emptyTLV = false;
			return (short)theValue.length;
		}
		else
		{
			// TODO: throw exception
			return -1;
		}	
	}
	
	public short init(PrimitiveBERTag tag, byte[] vArray, short vOff, short vLen)
	{
		if (vArray == null) throw new NullPointerException();
		
		if ((short)(vArray.length - vOff) ==  vLen)
		{	
			// tag
			this.theBERTag = tag;
			
			// value 
			Util.arrayCopy(vArray, vOff, theValue, MediatorFE.O, vLen);	
			this.emptyTLV = false;
			this.valueLength = vLen;
			
			return (short)theValue.length;
		}
		else
		{
			throw new ArrayIndexOutOfBoundsException(); 
		}
	}
	
	public short size() 
	{
		if (valueLength > 127) return (short) (theValue.length + this.theBERTag.tagSizeInBytes + 2 );
		return (short) (theValue.length + this.theBERTag.tagSizeInBytes + 1 );
	}

	// TODO: Test
	public short toBytes(byte[] outBuf, short bOff) throws ArrayIndexOutOfBoundsException, NullPointerException 
	{
		if (outBuf == null) throw new NullPointerException();
		
		if ((short)(outBuf.length + bOff) >=  (short)(this.getLength() + 2))
		//if ((short)(outBuf.length - bOff) >=  (short)(this.getLength()))
		{	
			short offset = bOff;
			
			// tag
			this.theBERTag.toBytes(outBuf, offset);			
			if (this.theBERTag.size() == 1) offset++;
			else if (this.theBERTag.size() == 2) offset += 2;
			else throw new NullPointerException(); 
			
			// length && value
			if(this.valueLength < 128) 
			{
				outBuf[offset] = (byte)valueLength;
				offset++;	
			}
			if(this.valueLength > 127 && this.valueLength < 256) 
			{
				outBuf[offset] = (byte)0x81;
				outBuf[(short)(offset + 1)] = (byte)valueLength;
				offset += 2;
			}
			
			if(this.valueLength > 255 && this.valueLength < 32767) 
			{
				outBuf[offset] = (byte)0x82;
				outBuf[(short)(offset + 1)] = MediatorFE.shortOnByteArray(valueLength)[1];
				outBuf[(short)(offset + 2)] = MediatorFE.shortOnByteArray(valueLength)[0];
				offset += 3;
			}
			
			Util.arrayCopy(theValue, (short)0 , outBuf, offset, (short)theValue.length);
			
			//Util.arrayCopy(new byte[]{1,2}, (short)0 , outBuf, offset, (short)2);
			//Util.arrayCopy(theValue, (short)0  , outBuf, (short) (offset + bOff), (short)theValue.length);
			
			return (short)outBuf.length;
		}
		else 
			throw new ArrayIndexOutOfBoundsException(); 
	}
}
